﻿// 功能：透明背景的全屏弹出对话框
// 描述：
// 作者：温伟鹏
// 日期：2010/9/10 12:22:16

using System;
using System.Runtime.InteropServices;
using MeizuSDK.Drawing;
using System.Drawing;

namespace MeizuSDK.Presentation
{
    /// <summary>
    /// 透明背景的全屏弹出对话框
    /// </summary>
    public class PopupDialog : IMzWindow, IDisposable
    {
        #region 常量
        /// <summary>
        /// 默认的对话框第一个按钮的Id，为了防止与其他按钮Id重复
        /// </summary>
        internal const int FirstButtonId = 0x12000000;
        #endregion

        #region 委托
        /// <summary>
        /// 对话框按钮单击事件委托
        /// </summary>
        /// <param name="uButtonId"></param>
        /// <returns></returns>
        delegate void PopupDialogButtonClick(uint uButtonId);
        /// <summary>
        /// PostOwnerMessage
        /// </summary>
        /// <param name="message"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        delegate void PopupDialogPostOwnerMessage(uint message, uint wParam, uint lParam);
        #endregion

        #region DllImport
        /// <summary>
        /// 对话框构造函数
        /// </summary>
        /// <param name="onMzCommand"></param>
        /// <param name="mzDefWndProc"></param>
        /// <param name="postOwnerMessage"></param>
        /// <param name="paintWin"></param>
        /// <param name="buttonClick"></param>
        /// <returns></returns>
        [DllImport("MZFCWrapper.dll")]
        private static extern IntPtr MzPopupDialogCtor(OnMzCommandFunc onMzCommand, MzDefWndProcFunc mzDefWndProc,
            PopupDialogPostOwnerMessage postOwnerMessage, PaintWinFunc2 paintWin, PopupDialogButtonClick buttonClick);
        /// <summary>
        /// 销毁对话框资源
        /// </summary>
        /// <param name="pObj"></param>
        [DllImport("MZFCWrapper.dll")]
        private static extern void MzPopupDialogDispose(IntPtr pObj);
        /// <summary>
        /// 获取对话框句柄
        /// </summary>
        /// <param name="pObj"></param>
        /// <returns></returns>
        [DllImport("MZFCWrapper.dll")]
        private static extern IntPtr MzPopupDialogGetHWND(IntPtr pObj);
        /// <summary>
        /// 对话框初始化
        /// </summary>
        /// <param name="pObj"></param>
        /// <param name="hWnd"></param>
        /// <param name="pViewHandle"></param>
        /// <param name="bPostCommandMessage"></param>
        /// <param name="bBGTransparent"></param>
        /// <returns></returns>
        [DllImport("MZFCWrapper.dll")]
        private static extern bool MzPopupDialogDlgInitialize(IntPtr pObj, IntPtr hWnd, IntPtr pViewHandle, bool bPostCommandMessage, bool bBGTransparent);
        /// <summary>
        /// 对话框初始化
        /// </summary>
        /// <param name="pObj"></param>
        /// <param name="hWnd"></param>
        /// <param name="pViewHandle"></param>
        /// <param name="lpszTitle"></param>
        /// <param name="bPostCommandMessage"></param>
        /// <param name="bBGTransparent"></param>
        /// <param name="bExitOnLock"></param>
        /// <param name="bDisableOwner"></param>
        /// <returns></returns>
        [DllImport("MZFCWrapper.dll")]
        private static extern bool MzPopupDialogDlgInitializeEx(IntPtr pObj, IntPtr hWnd, IntPtr pViewHandle, string lpszTitle, bool bPostCommandMessage, bool bBGTransparent, bool bExitOnLock, bool bDisableOwner);
        /// <summary>
        /// 显示对话框
        /// </summary>
        /// <param name="pObj"></param>
        /// <param name="bInitVisible"></param>
        /// <param name="style">对话框样式 默认：WS_POPUP=0x80000000L</param>
        /// <param name="exstyle">0</param>
        [DllImport("MZFCWrapper.dll")]
        private static extern void MzPopupDialogDlgDoModel(IntPtr pObj, bool bInitVisible, uint style, uint exstyle);
        /// <summary>
        /// 关闭对话框
        /// </summary>
        /// <param name="pObj"></param>
        /// <param name="nRet"></param>
        /// <returns></returns>
        [DllImport("MZFCWrapper.dll")]
        private static extern bool MzPopupDialogDlgEndModel(IntPtr pObj, uint nRet);
        /// <summary>
        /// 增加用户按钮
        /// </summary>
        /// <param name="pObj"></param>
        /// <param name="lpszText">按钮文本</param>
        /// <param name="pImage">图标</param>
        /// <param name="pImagePressed">按钮按下时的图标</param>
        /// <returns></returns>
        [DllImport("MZFCWrapper.dll")]
        private static extern bool MzPopupDialogAddUserButton(IntPtr pObj, string lpszText, IntPtr pImage, IntPtr pImagePressed);
        /// <summary>
        /// 移除所有用户按钮
        /// </summary>
        /// <param name="pObj"></param>
        /// <returns></returns>
        [DllImport("MZFCWrapper.dll")]
        private static extern bool MzPopupDialogRemoveAllUserButton(IntPtr pObj);
        /// <summary>
        /// 设置第一个按钮的Id
        /// </summary>
        /// <param name="pObj"></param>
        /// <param name="uID"></param>
        [DllImport("MZFCWrapper.dll")]
        private static extern void MzPopupDialogSetFirstButtonID(IntPtr pObj, uint uID);
        /// <summary>
        /// 获取第一个按钮的Id
        /// </summary>
        /// <param name="pObj"></param>
        /// <returns></returns>
        [DllImport("MZFCWrapper.dll")]
        private static extern uint MzPopupDialogGetFirstButtonID(IntPtr pObj);
        /// <summary>
        /// 获取对话框中按钮数量
        /// </summary>
        /// <param name="pObj"></param>
        /// <returns></returns>
        [DllImport("MZFCWrapper.dll")]
        private static extern uint MzPopupDialogGetButtonCount(IntPtr pObj);
        /// <summary>
        /// 对话框是否启用休眠
        /// </summary>
        /// <param name="pObj"></param>
        /// <param name="bEnable"></param>
        /// <returns></returns>
        [DllImport("MZFCWrapper.dll")]
        private static extern bool MzPopupDialogEnableDialogSleep(IntPtr pObj, bool bEnable);
        /// <summary>
        /// 设置对话框自动关闭时间
        /// </summary>
        /// <param name="pObj"></param>
        /// <param name="uTimeOut"></param>
        /// <returns></returns>
        [DllImport("MZFCWrapper.dll")]
        private static extern bool MzPopupDialogSetDialogAutoExit(IntPtr pObj, uint uTimeOut);
        /// <summary>
        /// 设置对话框是否在锁屏之后关闭
        /// </summary>
        /// <param name="pObj"></param>
        /// <param name="bExit"></param>
        [DllImport("MZFCWrapper.dll")]
        private static extern void MzPopupDialogSetExitOnLockPhone(IntPtr pObj, bool bExit);
        /// <summary>
        /// 获取对话框是否在锁屏之后关闭
        /// </summary>
        /// <param name="pObj"></param>
        /// <returns></returns>
        [DllImport("MZFCWrapper.dll")]
        private static extern bool MzPopupDialogIsExitOnLockPhone(IntPtr pObj);
        /// <summary>
        /// 设置对话框是否在按下M键后关闭
        /// </summary>
        /// <param name="pObj"></param>
        /// <param name="bExit"></param>
        [DllImport("MZFCWrapper.dll")]
        private static extern void MzPopupDialogSetExitOnMKey(IntPtr pObj, bool bExit);
        /// <summary>
        /// 获取对话框是否在按下M键关闭
        /// </summary>
        /// <param name="pObj"></param>
        /// <returns></returns>
        [DllImport("MZFCWrapper.dll")]
        private static extern bool MzPopupDialogIsExitOnMKey(IntPtr pObj);

        [DllImport("MZFCWrapper.dll")]
        private static extern bool MzPopupDialogSetCurrentView(IntPtr pObj, IntPtr pViewHandle);

        [DllImport("MZFCWrapper.dll")]
        private static extern IntPtr MzPopupDialogGetCurrentView(IntPtr pObj);
        /// <summary>
        /// 设置背景图片
        /// </summary>
        /// <param name="pObj"></param>
        /// <param name="hbmpBG"></param>
        /// <returns></returns>
        [DllImport("MZFCWrapper.dll")]
        private static extern bool MzPopupDialogSetBGImage(IntPtr pObj, IntPtr hbmpBG);

        [DllImport("MZFCWrapper.dll")]
        private static extern IntPtr MzPopupDialogGetBGImage(IntPtr pObj);

        [DllImport("MZFCWrapper.dll")]
        private static extern bool MzPopupDialogIsContinue(IntPtr pObj);

        [DllImport("MZFCWrapper.dll")]
        private static extern uint MzPopupDialogGetEndResult(IntPtr pObj);

        [DllImport("MZFCWrapper.dll")]
        private static extern bool MzPopupDialogShowDialogAnimate(IntPtr pObj, bool bShow, uint uAnimateType);

        [DllImport("MZFCWrapper.dll")]
        private static extern void MzPopupDialogLockDialogData(IntPtr pObj);

        [DllImport("MZFCWrapper.dll")]
        private static extern void MzPopupDialogUnlockDialogData(IntPtr pObj);

        [DllImport("MZFCWrapper.dll")]
        private static extern uint MzPopupDialogGetFirstUserWinID();

        [DllImport("MZFCWrapper.dll")]
        private static extern uint MzPopupDialogGetFirstUserTimerID();
        #endregion

        #region 私有变量

        #region 委托
        /// <summary>
        /// 截获命令
        /// </summary>
        private OnMzCommandFunc onMzCommand;
        /// <summary>
        /// 截获消息
        /// </summary>
        private MzDefWndProcFunc mzDefWndProc;
        /// <summary>
        /// 发送消息
        /// </summary>
        private PopupDialogPostOwnerMessage postOwnerMessage;
        /// <summary>
        /// 对话框重绘委托
        /// </summary>
        private PaintWinFunc2 paintWin;
        /// <summary>
        /// 对话框按钮单击事件
        /// </summary>
        private PopupDialogButtonClick buttonClick;
        #endregion

        /// <summary>
        /// 用户自定义按钮集合
        /// </summary>
        private PopupDialogButtonCollection buttonCollection;
        /// <summary>
        /// 对话框运行结果
        /// </summary>
        private DialogResult dialogResult;
        /// <summary>
        /// 对话框句柄
        /// </summary>
        private IntPtr m_hWnd;
        /// <summary>
        /// 对话框所有者
        /// </summary>
        private IMzWindow pOwner;
        /// <summary>
        /// 指向对话框的指针
        /// </summary>
        private IntPtr pObj;
        /// <summary>
        /// 对话框是否已经被销毁
        /// </summary>
        private bool isDisposed;
        /// <summary>
        /// 对话框是否已经打开
        /// </summary>
        private bool isShown;
        /// <summary>
        /// 主视图
        /// </summary>
        private Control m_View;
        /// <summary>
        /// 对话框标题
        /// </summary>
        private string title;

        //private bool postCmdMsg;
        /// <summary>
        /// 对话框背景是否透明
        /// </summary>
        private bool bgTransparent;

        //private bool exitOnLock;

        //private bool disableOwner;

        private Image bgImage;
        /// <summary>
        /// 对话框打开时的动画效果
        /// </summary>
        private AnimationType animateIn;
        /// <summary>
        /// 对话框关闭时的动画效果
        /// </summary>
        private AnimationType animateOut;
        /// <summary>
        /// 对话框关闭方式
        /// </summary>
        private PopupDialogCloseMode closeMode;
        /// <summary>
        /// 对话框在到达此时间（单位：毫秒）后自动关闭。如果CloseMode=AutoClose，则此属性才有效。
        /// </summary>
        private uint autoCloseTimeOut;
        #endregion

        #region 公共属性
        /// <summary>
        /// 获取当前对话框是否已经被释放
        /// </summary>
        internal bool IsDisposed
        {
            get
            {
                return this.isDisposed;
            }
        }
        /// <summary>
        /// 获取或设置对话框打开时的动画效果
        /// </summary>
        public AnimationType AnimateIn
        {
            get
            {
                return this.animateIn;
            }
            set
            {
                this.animateIn = value;
                if (!isShown)
                    MzPopupDialogShowDialogAnimate(Handle, true, (uint)this.animateIn);
            }
        }
        /// <summary>
        /// 获取或设置对话框关闭时的动画效果
        /// </summary>
        public AnimationType AnimateOut
        {
            get
            {
                return this.animateOut;
            }
            set
            {
                this.animateOut = value;
                if (!isShown)
                    MzPopupDialogShowDialogAnimate(Handle, false, (uint)this.animateOut);
            }
        }
        /// <summary>
        /// 获取或设置对话框背景图
        /// </summary>
        public Image BgImage
        {
            get
            {
                return bgImage;
            }
            set
            {
                this.bgImage = value;

                if (!isShown)
                {
                    MzPopupDialogSetBGImage(Handle, ((Bitmap)bgImage).GetHbitmap());
                }
            }
        }
        /// <summary>
        /// 获取对话框当前是否正在运行
        /// </summary>
        public bool IsContinue
        {
            get
            {
                return (isShown && MzPopupDialogIsContinue(Handle));
            }
        }
        /// <summary>
        /// 获取对话框句柄
        /// </summary>
        public IntPtr HWnd
        {
            get
            {
                return this.m_hWnd;
            }
        }
        /// <summary>
        /// 获取打开此对话框的窗口
        /// </summary>
        public IMzWindow ParentWindow
        {
            get {
                return this.pOwner;
            }
        }
        /// <summary>
        /// 获取指向对话框的指针
        /// </summary>
        public IntPtr Handle
        {
            get
            {
                return pObj;
            }
        }
        /// <summary>
        /// 获取对话框运行结果
        /// </summary>
        public DialogResult DialogResult
        {
            get
            {
                return this.dialogResult;
            }
            protected set
            {
                this.dialogResult = value;
            }
        }
        /// <summary>
        /// 获取或设置对话框主视图
        /// </summary>
        public Control MainView
        {
            get
            {
                return m_View;
            }
            set
            {
                if (!isShown)
                    m_View = value;
            }
        }
        /// <summary>
        /// 获取或设置对话框标题
        /// </summary>
        public string Title
        {
            get
            {
                return this.title;
            }
            set
            {
                if (!isShown)
                    this.title = value;
            }
        }
        /// <summary>
        /// 获取或设置对话框背景是否透明
        /// </summary>
        public bool BgTransparent
        {
            get
            {
                return this.bgTransparent;
            }
            set
            {
                if (!isShown)
                    this.bgTransparent = value;
            }
        }
        /// <summary>
        /// 获取对话框中用户自定义按钮集合
        /// </summary>
        public PopupDialogButtonCollection Buttons
        {
            get
            {
                if (buttonCollection == null)
                {
                    buttonCollection = new PopupDialogButtonCollection(this);
                }
                return buttonCollection;
            }
        }
        /// <summary>
        /// 获取或设置对话框关闭方式
        /// </summary>
        public PopupDialogCloseMode CloseMode
        {
            get
            {
                return this.closeMode;
            }
            set
            {
                if (!isShown)
                    this.closeMode = value;
            }
        }
        /// <summary>
        /// 获取或设置一个值，指示对话框在经过指定时间后自动关闭。单位：毫秒
        /// </summary>
        public uint AutoCloseTimeOut
        {
            get
            {
                return this.autoCloseTimeOut;
            }
            set
            {
                if (!isShown)
                    this.autoCloseTimeOut = value;
            }
        }
        #endregion

        #region 构造函数
        /// <summary>
        /// 构造对话框实例
        /// </summary>
        public PopupDialog()
            : this(null)
        {

        }
        /// <summary>
        /// 构造对话框实例
        /// </summary>
        /// <param name="view">对话框内容布局视图</param>
        public PopupDialog(Control view)
            : this(string.Empty, view)
        {

        }
        /// <summary>
        /// 构造对话框实例
        /// </summary>
        /// <param name="title">对话框标题</param>
        /// <param name="view">对话框内容布局视图</param>
        public PopupDialog(string title, Control view)
        {
            onMzCommand = new OnMzCommandFunc(OnMzCommand);
            mzDefWndProc = new MzDefWndProcFunc(WndProc);
            postOwnerMessage = new PopupDialogPostOwnerMessage(PostOwnerMessage);
            paintWin = new PaintWinFunc2(PaintWin);
            buttonClick = new PopupDialogButtonClick(OnButtonClick);

            // 构建对话框
            pObj = MzPopupDialogCtor(onMzCommand, mzDefWndProc, postOwnerMessage,
                paintWin, buttonClick);

            // 获取对话框的句柄
            m_hWnd = MzPopupDialogGetHWND(pObj);

            // 将对话框所有者置空
            pOwner = null;

            // 设置对话框第一个按钮的Id
            MzPopupDialogSetFirstButtonID(Handle, FirstButtonId);
            
            // 设置对话框中要显示的视图
            m_View = view;

            this.title = title;
            this.isShown = false;
            this.closeMode = PopupDialogCloseMode.UseFirstButton;
            this.autoCloseTimeOut = 3000;// 自动关闭时间为3s
        }
        #endregion

        #region 函数
        /// <summary>
        /// 当对话框接收到WM_COMMAND消息时调用此函数
        /// </summary>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        protected virtual void OnMzCommand(uint wParam, uint lParam)
        {
        }
        /// <summary>
        /// 处理对话框消息
        /// </summary>
        /// <param name="message"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        protected virtual uint WndProc(uint message, uint wParam, uint lParam)
        {
            return 0;
        }
        /// <summary>
        /// 截获对话框向对话框Owner发送的消息
        /// </summary>
        /// <param name="message"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        protected virtual void PostOwnerMessage(uint message, uint wParam, uint lParam)
        {
        }
        /// <summary>
        /// 对话框自绘
        /// </summary>
        /// <param name="hdc"></param>
        /// <param name="prcUpdate"></param>
        private void PaintWin(IntPtr hdc, ref RECT prcUpdate)
        {
            if(hdc!=IntPtr.Zero)
            {
                using(Graphics g = Graphics.FromHdc(hdc))
                {
                    Rectangle rectUpdate = prcUpdate.ToRectangle();

                    OnPaint(g, rectUpdate);
                }
            }
        }
        /// <summary>
        /// 对话框自绘函数
        /// </summary>
        /// <param name="g"></param>
        /// <param name="rectUpdate"></param>
        protected virtual void OnPaint(Graphics g,Rectangle rectUpdate)
        {

        }
        /// <summary>
        /// 按钮被单击后，对话框会调用此函数
        /// </summary>
        /// <param name="uButtonID"></param>
        /// <returns></returns>
        private void OnButtonClick(uint uButtonID)
        {
            if (Buttons.Count > 0)
            {
                switch (closeMode)
                {
                    case PopupDialogCloseMode.UseSecondButton:
                        {
                            if (Buttons.Count > 2 && uButtonID == FirstButtonId + 2)
                            {
                                Close();
                                return;
                            }
                        }
                        break;
                    case PopupDialogCloseMode.UseThirdButton:
                        {
                            if (Buttons.Count > 1 && uButtonID == FirstButtonId + 1)
                            {
                                Close();
                                return;
                            }
                        }
                        break;
                    case PopupDialogCloseMode.UseFirstButton:
                        {
                            // 表示触发的是第一个按钮
                            if (uButtonID == FirstButtonId)
                            {
                                Close();
                                return;
                            }
                        }
                        break;
                }

                PopupDialogButton button = Buttons.GetButtonById(uButtonID);

                if (button != null)
                    button.RaiseClickEvent();
            }
        }
        /// <summary>
        /// 删除对话框中所有用户自定义的按钮
        /// </summary>
        internal void RemoveAllUserButtons()
        {
            MzPopupDialogRemoveAllUserButton(Handle);
        }
        /// <summary>
        /// 显示对话框
        /// </summary>
        public void ShowDialog()
        {
            ShowDialog(null);
        }
        /// <summary>
        /// 显示对话框
        /// </summary>
        /// <param name="owner">对话框所有者窗口</param>
        public void ShowDialog(IMzWindow owner)
        {
            pOwner = Application.MainWindow;

            if (owner != null)
            {
                pOwner = owner;
            }

            if (m_View != null)
            {
                // 初始化
                MzPopupDialogDlgInitializeEx(Handle, pOwner.HWnd, MainView.Handle, Title, true, bgTransparent, true, false);
            }

            // 设置对话框关闭方式
            if (closeMode == PopupDialogCloseMode.AutoClose)
            {
                try
                {
                    MzPopupDialogSetDialogAutoExit(Handle, autoCloseTimeOut);
                }
                catch (Exception)
                { }
            }

            // 重设按钮Id
            Buttons.ResetButtonsId();

            // 将按钮显示在对话框上
            for (int i = 0; i < Buttons.Count; i++)
            {
                try
                {
                    MzPopupDialogAddUserButton(Handle, Buttons[i].Text,
                        (Buttons[i].Image == null ? IntPtr.Zero : Buttons[i].Image.Handle),
                        (Buttons[i].PressedImage == null ? IntPtr.Zero : Buttons[i].PressedImage.Handle));
                }
                catch (Exception)
                { }
            }

            // 标志位设置为true
            isShown = true;

            MzPopupDialogDlgDoModel(Handle, true, 0x80000000, 0);
        }
        /// <summary>
        /// 关闭对话框
        /// </summary>
        public void Close()
        {
            isShown = false;

            try
            {
                MzPopupDialogDlgEndModel(Handle, 1);
            }
            catch (Exception)
            { }
            finally
            {
                Dispose();
                // 显示窗口 SW_SHOW=5
                NativeMethods.ShowWindow(ParentWindow.HWnd, NativeFormShowType.Show);
                // 将所有者窗口置前
                NativeMethods.SetForegroundWindow(ParentWindow.HWnd);
            }
        }
        /// <summary>
        /// 销毁资源
        /// </summary>
        public void Dispose()
        {
            Dispose(true);

            isDisposed = true;
        }
        /// <summary>
        /// 销毁资源
        /// </summary>
        /// <param name="disposing"></param>
        protected virtual void Dispose(bool disposing)
        {
            try
            {
                Buttons.Clear();

                if (m_View != null)
                    m_View.Dispose();

                MzPopupDialogDispose(Handle);
            }
            catch (Exception)
            { }
        }
        #endregion
    }

    /// <summary>
    /// 弹出式对话框关闭方式
    /// </summary>
    public enum PopupDialogCloseMode
    {
        /// <summary>
        /// 使用第一个按钮关闭
        /// </summary>
        UseFirstButton,
        /// <summary>
        /// 使用第二个按钮关闭
        /// </summary>
        UseSecondButton,
        /// <summary>
        /// 使用第三个按钮关闭
        /// </summary>
        UseThirdButton,
        /// <summary>
        /// 对话框自动关闭。必须设置AutoCloseTimeOut。单位：毫秒
        /// </summary>
        AutoClose
    }
}
